package com.romain.risotto.manager;


import java.util.ArrayList;
import java.util.List;

import org.andengine.engine.Engine;
import org.andengine.engine.camera.SmoothCamera;
import org.andengine.engine.camera.hud.HUD;
import org.andengine.engine.camera.hud.controls.AnalogOnScreenControl;
import org.andengine.engine.camera.hud.controls.AnalogOnScreenControl.IAnalogOnScreenControlListener;
import org.andengine.engine.camera.hud.controls.BaseOnScreenControl;
import org.andengine.entity.primitive.Rectangle;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.sprite.Sprite;
import org.andengine.extension.physics.box2d.PhysicsFactory;
import org.andengine.extension.physics.box2d.PhysicsWorld;
import org.andengine.input.touch.TouchEvent;
import org.andengine.opengl.vbo.VertexBufferObjectManager;
import org.andengine.util.math.MathUtils;

import android.opengl.GLES20;
import android.util.Log;
import android.util.SparseArray;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.romain.risotto.Constantes;
import com.romain.risotto.entities.Bullet;
import com.romain.risotto.entities.Rocher;
import com.romain.risotto.entities.Ship;
import com.romain.risotto.hud.ProgressBar;
import com.romain.risotto.texture.Textures;

public class GameManager  {

	public static final short CATEGORYBIT_WALL = 1;
	public static final short CATEGORYBIT_MY_BULLET = 2;
	public static final short CATEGORYBIT_OTHER_BULLET = 4;
	public static final short CATEGORYBIT_MY_SHIP = 8;
	public static final short CATEGORYBIT_OTHER_SHIP = 16;

	/* And what should collide with what. */
	public static final short MASKBITS_WALL = CATEGORYBIT_WALL  + CATEGORYBIT_MY_SHIP + CATEGORYBIT_OTHER_SHIP;
	public static final short MASKBITS_MY_BULLET = CATEGORYBIT_OTHER_SHIP; 
	public static final short MASKBITS_OTHER_BULLET = CATEGORYBIT_MY_SHIP; 
	public static final short MASKBITS_MY_SHIP = CATEGORYBIT_MY_SHIP+CATEGORYBIT_WALL; 
	public static final short MASKBITS_OTHER_SHIP = CATEGORYBIT_MY_BULLET; 

	public static final FixtureDef FIXTURE_WALL_DEF = PhysicsFactory.createFixtureDef(0, 0.1f, 0.8f, false, CATEGORYBIT_WALL, MASKBITS_WALL, (short)0);
	public static final FixtureDef FIXTURE_MY_SHIP_DEF = PhysicsFactory.createFixtureDef(1, 0.2f, 0.5f, false, CATEGORYBIT_MY_SHIP, MASKBITS_MY_SHIP, (short)0);
	public static final FixtureDef FIXTURE_OTHER_SHIP_DEF = PhysicsFactory.createFixtureDef(1, 0.5f, 0.5f, false, CATEGORYBIT_OTHER_SHIP, MASKBITS_OTHER_SHIP, (short)0);
	public static final FixtureDef FIXTURE_MY_BULLET_DEF = PhysicsFactory.createFixtureDef(1, 0.5f, 0.5f, false, CATEGORYBIT_MY_BULLET, MASKBITS_MY_BULLET, (short)0);
	public static final FixtureDef FIXTURE_OTHER_BULLET_DEF = PhysicsFactory.createFixtureDef(1, 0.5f, 0.5f, false, CATEGORYBIT_OTHER_BULLET, MASKBITS_OTHER_BULLET, (short)0);
	
	
	private static GameManager gameManager;
	private HUD mhud;
	private Engine engine;
	private Scene scene;
	private SmoothCamera camera;
	private VertexBufferObjectManager vbom;
	private final SparseArray<Ship> ships;
	private final List<Rocher> asteroids;
	private Ship mainShip = null;
	private ServerCom connection;
	private short playerId;

	public PhysicsWorld physicWorld;
	public ProgressBar progress;
	
	public short getPlayerId() {
		return playerId;
	}

	public List<Rocher> getAsteroids() {
		return asteroids;
	}

	public Ship getMainShip() {
		return mainShip;
	}

	public SparseArray<Ship> getShips() {
		return ships;
	}

	public Engine getEngine() {
		return engine;
	}

	private GameManager() {
		ships = new SparseArray<Ship>();
		asteroids = new ArrayList<Rocher>();
		physicWorld = new PhysicsWorld(new Vector2(0,0), true);
	}

	public static GameManager getInstance() {
		if (gameManager == null) {
			gameManager = new GameManager();
		}
		return gameManager;
	}

	public void init(Engine _engine, Scene _scene, SmoothCamera _camera,
			VertexBufferObjectManager _vbom) {
		scene = _scene;
		engine = _engine;
		camera = _camera;
		vbom = _vbom;
		playerId = (short) (8000 * Math.random());

	}

	public void start() {
		
		//CREATION DU BACKGROUND
		createBackground();
		
		// CREATION DES BORDURES
		createBorders();
		
		// CREATION DE NOTRE VAISSEAU
		mainShip = createShip(false,
				(int) (Math.random() * Constantes.FIELD_WIDTH),	(int) (Math.random() * Constantes.FIELD_HEIGHT),
				(float) (Math.random() * Math.PI * 2),true);
		mainShip.setId((short) 1234);
		camera.setChaseEntity(mainShip);
		
		//CREATION DES CONTROLES
		createHUDControls();
		
		
		scene.registerUpdateHandler(physicWorld);
		
		
//		for (int i = 0; i < 5; i++) {
//			Rocher rocher = new Rocher((float) Math.random() * 1000,
//					(float) Math.random() * 1000, vbom);
//			scene.attachChild(rocher);
//
//			this.addAsteroid(rocher);
//		}
		

		connection.sendCreationPlayer(mainShip.getId(), mainShip.getX(),
				mainShip.getY(), mainShip.getDirection());
		
	}

	private void createHUDControls() {
		mhud = new HUD();
		camera.setHUD(mhud);
		final float yPAD = Constantes.CAMERA_HEIGHT
				- Textures.texturePad.getHeight();
		final AnalogOnScreenControl velocityOnScreenControl = new AnalogOnScreenControl(
				0, yPAD, camera, Textures.texturePad, Textures.textureBouton,
				0.1f, vbom, new IAnalogOnScreenControlListener() {
					@Override
					public void onControlChange(
							final BaseOnScreenControl pBaseOnScreenControl,
							final float pValueX, final float pValueY) {
						if (pValueX != 0 && pValueY != 0) {
							float rot = (float) Math.atan2(pValueX, -pValueY);
							mainShip.setDirection(rot);
						}
					}

					@Override
					public void onControlClick(
							AnalogOnScreenControl pAnalogOnScreenControl) {
					}

				});
		velocityOnScreenControl.getControlBase().setBlendFunction(
				GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
		velocityOnScreenControl.getControlBase().setAlpha(0.5f);
		velocityOnScreenControl.getControlKnob().setScale(1.4f);
		scene.setChildScene(velocityOnScreenControl);

		// BOUTONS SHOOT
		Sprite boutonShoot = new Sprite(camera.getWidth() - 180,
				camera.getHeight() - 90, Textures.textureBouton, vbom) {
			@Override
			public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
					float pTouchAreaLocalX, float pTouchAreaLocalY) {
				if (pSceneTouchEvent.isActionDown()) {
					Log.d("", "shoot!!");
					GameManager.this.mainShipShoot();
				}

				return true;
			};
		};
		boutonShoot.setScale(1.5f);
		// BOUTONS  GAZ
		Sprite boutonGaz = new Sprite(camera.getWidth() - 90,
				camera.getHeight() - 90, Textures.textureBouton, vbom) {
			@Override
			public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
					float pTouchAreaLocalX, float pTouchAreaLocalY) {
				if (pSceneTouchEvent.isActionDown()) {
					mainShip.setGaz(true);
					camera.setZoomFactor(0.5f);
				} else if (pSceneTouchEvent.isActionUp()
						|| pSceneTouchEvent.isActionOutside()
						|| pSceneTouchEvent.isActionCancel()) {
					mainShip.setGaz(false);
					camera.setZoomFactor(1.0f);
				}
				return true;
			};
		};
		boutonGaz.setScale(1.5f);

		mhud.registerTouchArea(boutonShoot);
		mhud.attachChild(boutonShoot);
		mhud.registerTouchArea(boutonGaz);
		mhud.attachChild(boutonGaz);
		
		progress = new ProgressBar(2, 2, 100, 12, vbom);
		mhud.attachChild(progress);
		progress.setProgressColor(0, 1f, 0, 1);
		progress.setBackColor(0, 0, 0, 1);
		progress.setProgress(30);
	}

	private void createBackground() {
		Textures.textureBG.setTextureWidth(Textures.textureBG.getWidth()
				* (Constantes.FIELD_WIDTH / Textures.textureBG.getWidth()));
		Textures.textureBG.setTextureHeight(Textures.textureBG.getHeight()
				* (Constantes.FIELD_HEIGHT / Textures.textureBG.getHeight()));
		Sprite bg = new Sprite(0, 0, Textures.textureBG, vbom);
		scene.attachChild(bg);
	}
	private void createBorders(){
		final Rectangle ground = new Rectangle(0, Constantes.FIELD_HEIGHT - 2, Constantes.FIELD_WIDTH, 2, vbom);
		final Rectangle roof = new Rectangle(0, 0, Constantes.FIELD_WIDTH, 2, vbom);
		final Rectangle left = new Rectangle(0, 0, 2, Constantes.FIELD_HEIGHT, vbom);
		final Rectangle right = new Rectangle(Constantes.FIELD_WIDTH - 2, 0, 2, Constantes.FIELD_HEIGHT, vbom);

		PhysicsFactory.createBoxBody(physicWorld, ground, BodyType.StaticBody, FIXTURE_WALL_DEF);
		PhysicsFactory.createBoxBody(physicWorld, roof, BodyType.StaticBody, FIXTURE_WALL_DEF);
		PhysicsFactory.createBoxBody(physicWorld, left, BodyType.StaticBody, FIXTURE_WALL_DEF);
		PhysicsFactory.createBoxBody(physicWorld, right, BodyType.StaticBody, FIXTURE_WALL_DEF);
		
		scene.attachChild(ground);
		scene.attachChild(roof);
		scene.attachChild(left);
		scene.attachChild(right);
	}
	
	
	private Ship createShip(boolean isManuelUp, int x, int y, float pdir,boolean isMain) {
		Ship s = new Ship(isManuelUp, x, y, Textures.textureShip, vbom,isMain);
		s.setDirection(pdir);
		s.setRotation(MathUtils.radToDeg(pdir));
		scene.attachChild(s);
		return s;
	}

	

	public void addShip(Ship ship) {

	}

	public void addAsteroid(Rocher rocher) {
		asteroids.add(rocher);
	}

	public void registerDead(Ship ship) {
		ships.remove(ship.getId());

	}

	public void updateMainShip(Ship ship) {
		if (ship == mainShip) {
			camera.updateChaseEntity();
		}
	}

	public void mainShipShoot() {
		Bullet b = new Bullet(mainShip, Textures.textureBullet, vbom);
		//b.setScale(0.5f);
		scene.attachChild(b);
	}

	public void setClientConnection(ServerCom serverCom) {
		connection = serverCom;
		serverCom.setGameManager(this);

	}

	public void onExtCreatePlayer(short idPlayer, int x, int y, float direction) {
		Ship s = createShip(true, x, y, direction,false);
		s.setId(idPlayer);
		s.setRotation(MathUtils.radToDeg(direction));
		ships.append(s.getId(), s);

	}


}
